﻿using System;
using System.Linq;
using System.Threading;
using System.Windows;
using nRoute.Components.Composition;
using nRoute.Navigation;
#if (WINRT)
using Windows.UI.Xaml;
using Windows.UI.Xaml.Markup;
#else
using nRoute.Controllers;
using nRoute.SiteMaps;
using System.Windows.Markup;
#endif

namespace nRoute.ApplicationServices
{
#if (WINRT)
    //[ContentProperty(Name = "SiteMapProvider")]
#else
    [ContentProperty("SiteMapProvider")]
#endif
    public partial class nRouteApplicationService
    {
        private static nRouteApplicationService _defaultInstance;

        private readonly WriteOnce<IResourceCatalog> _resourceCatalog = new WriteOnce<IResourceCatalog>();
#if (!WINRT)
        private readonly WriteOnce<ISiteMapProvider> _siteMapProvider = new WriteOnce<ISiteMapProvider>();
#endif

        public event EventHandler<InitializedEventArgs> Initialized;

#region Static Property

        public static nRouteApplicationService Current
        {
            get
            {
                if (_defaultInstance == null)
                {
#if (SILVERLIGHT)
                    Interlocked.Exchange(ref _defaultInstance, Application.Current.ApplicationLifetimeObjects.OfType<nRouteApplicationService>().FirstOrDefault());
#elif (WINRT)
                    Interlocked.Exchange(ref _defaultInstance, (nRouteApplicationService)Application.Current.Resources.FirstOrDefault((kv) => kv.Value is nRouteApplicationService).Value);
#else
                    Interlocked.Exchange(ref _defaultInstance, Application.Current.Resources.Values.OfType<nRouteApplicationService>().FirstOrDefault());
#endif
                }
                return _defaultInstance;
            }
        }

#endregion

#region Properties

        public IResourceCatalog ResourceCatalog
        {
            get { return _resourceCatalog.Value; }
            set { _resourceCatalog.Value = value; }
        }

#if (!WINRT)

        public ISiteMapProvider SiteMapProvider
        {
            get { return _siteMapProvider.Value; }
            set { _siteMapProvider.Value = value; }
        }

#endif

#endregion

#region Helpers

        protected virtual void OnInitialized()
        {
            var _resourceCatalogEx = _resourceCatalog.Value as IResourceCatalogEx;
            if (_resourceCatalogEx != null)
            {
                NavigationService.Initialize(_resourceCatalogEx.TypeBuilder);
#if (!WINRT)
                ControllerService.Initialize(_resourceCatalogEx.TypeBuilder);
                SiteMapService.Initialize();
#endif
            }

            if (Initialized != null) Initialized(this, new InitializedEventArgs(_resourceCatalog.Value));
#if (WINRT)
            _initializationCoordinator.SetResult(true);
#endif
        }

#endregion

#region Internal Class

        private class WriteOnce<T>
        {
            private const string VALUE_CAN_ONLY_BE_SET_ONCE = "Value of type {0}, can only be set once";

            private T _value;
            private int _flag = 0;

            public bool ValueSet
            {
                get { return (_flag != 0); }
            }

            public T Value
            {
                get { return _value; }
                set
                {
                    if (Interlocked.Add(ref _flag, 1) > 1)
                    {
                        throw new InvalidOperationException(string.Format(VALUE_CAN_ONLY_BE_SET_ONCE, typeof(T).FullName));
                    }
                    _value = value;
                }
            }
        }

#endregion

    }
}
